package com.tcoding.client.components.search;

import com.jfoenix.controls.*;
import com.jfoenix.controls.cells.editors.TextFieldEditorBuilder;
import com.jfoenix.controls.cells.editors.base.GenericEditableTreeTableCell;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import com.jfoenix.svg.SVGGlyph;
import com.tcoding.client.bean.CustomerBoxEditorModel;
import com.tcoding.client.bean.SearchItem;
import com.tcoding.client.components.editor.ComboBoxEditorBuilder;
import com.tcoding.client.extend.jfoenix.SnackbarExtend;
import com.tcoding.client.model.CustomerSearchModel;
import com.tcoding.client.service.Request;
import com.tcoding.client.service.feign.admin.CustomerSearchFeign;
import com.tcoding.client.utils.SvgGraphicUtil;
import com.tcoding.core.entity.CustomerSearchProgramme;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.context.ActionHandler;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.FlowActionHandler;
import io.datafx.controller.flow.context.ViewFlowContext;
import io.datafx.core.concurrent.ProcessChain;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventTarget;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.util.Callback;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.ArrayList;

/**
 * @author 唐全成
 * @Date: 2022/7/21 17:11
 * @description
 **/
@ViewController(value = "/fxml/search/customer_search.fxml", title = "高级查询测试")
public class CustomerSearchController {

    @ActionHandler
    private FlowActionHandler actionHandler;
    @FXML
    private StackPane rootPane;

    @FXML
    private StackPane rightPane;

    @FXML
    private StackPane leftPane;

    @FXMLViewFlowContext
    private ViewFlowContext flowContext;

    @FXML
    private JFXRippler addProgramme;

    @FXML
    private JFXRippler removeProgramme;

    @FXML
    private JFXRippler editProgramme;

    @FXML
    private JFXRippler addItem;

    @FXML
    private JFXRippler removeItem;

    @Inject
    private CustomerSearchModel customerSearchModel;
    /**
     * sql运算
     */
    private ObservableList<CustomerBoxEditorModel> actionItems;
    /**
     * 逻辑运算
     */
    private ObservableList<CustomerBoxEditorModel> logicItems;
    /**
     * 组标记
     */
    private ObservableList<CustomerBoxEditorModel> groupTagItems;

    JFXTreeTableView<SearchItem> treeView;

    private ObservableList<SearchItem> searchDatas;

    private TreeView leftTreeView;

    private SnackbarExtend snackbar;

    /**
     * 作用域名称
     */
    private String realmName;

    private String editingProgrammeField;


    @PostConstruct
    public void init() {
        Object actionName = flowContext.getRegisteredObject(String.class);
        this.realmName = actionName.toString();
        snackbar = new SnackbarExtend(rootPane, "WARNING");
        snackbar.setPrefWidth(300);
        searchDatas = FXCollections.observableArrayList();
        final TreeItem<SearchItem> root = new RecursiveTreeItem<>(searchDatas, RecursiveTreeObject::getChildren);
        treeView = new JFXTreeTableView<>(root);
        if (actionItems == null) {
            ObservableList<CustomerBoxEditorModel> innerList = FXCollections.observableArrayList();
            actionItems = new SimpleListProperty<>(innerList);
        }
        //初始化sql操作
        actionItems.addAll(new ArrayList<CustomerBoxEditorModel>() {{
            add(new CustomerBoxEditorModel("=", "="));
            add(new CustomerBoxEditorModel("!=", "!="));
            add(new CustomerBoxEditorModel(">", ">"));
            add(new CustomerBoxEditorModel("<", "<"));
            add(new CustomerBoxEditorModel(">=", ">="));
            add(new CustomerBoxEditorModel("<=", "<="));

        }});

        if (logicItems == null) {
            ObservableList<CustomerBoxEditorModel> innerList = FXCollections.observableArrayList();
            logicItems = new SimpleListProperty<>(innerList);
        }
        //初始化sql操作
        logicItems.addAll(new ArrayList<CustomerBoxEditorModel>() {{
            add(new CustomerBoxEditorModel("and", "and"));
            add(new CustomerBoxEditorModel("or", "or"));
            add(new CustomerBoxEditorModel(")", ")"));
        }});
        if (groupTagItems == null) {
            ObservableList<CustomerBoxEditorModel> innerList = FXCollections.observableArrayList();
            groupTagItems = new SimpleListProperty<>(innerList);
        }
        //初始化sql操作
        groupTagItems.addAll(new ArrayList<CustomerBoxEditorModel>() {{
            add(new CustomerBoxEditorModel("(", "("));
            add(new CustomerBoxEditorModel(" ", " "));
        }});
        //构建左侧树形
        buildLeftList();
        //构建右侧编辑表格
        buildTable();
        //初始化点击事件
        initActions();

        customerSearchModel.getSearchDatas().bindBidirectional(new SimpleListProperty<>(searchDatas));
    }

    private void cascadeRemoveLeaf(TreeItem<Label> parent, TreeItem<Label> leaf) {

        if (parent == null || parent.getValue() == null) {
            return;
        }
        ObservableList<TreeItem<Label>> children = parent.getChildren();

        for (TreeItem<Label> child : children) {
            if (child.equals(leaf)) {

                Label value = leaf.getValue();
                Integer programmeId = (Integer)value.getGraphic().getUserData();

                removeProgramme(programmeId);
                parent.getChildren().remove(leaf);
                break;
            }
            if (child.getChildren().size() > 0) {
                cascadeRemoveLeaf(child, leaf);
            }
        }
    }

    private void buildLeftList() {

        ProcessChain.create()
                .addSupplierInExecutor(() -> Request.connector(CustomerSearchFeign.class).getCustomerSearchProgrammeList(realmName))
                .addConsumerInPlatformThread(rel -> {
                    leftTreeView = new TreeView();
                    SVGGlyph svgGlyph = SvgGraphicUtil.buildSvgGraphic("folder-o", 12, Color.GRAY);
                    svgGlyph.setUserData(0);
                    TreeItem<Label> rootItem = new TreeItem<>(new Label("root",svgGlyph));
                    leftTreeView.setRoot(rootItem);
                    rootItem.setExpanded(true);
                    for (CustomerSearchProgramme programme : rel) {
                        if (programme.getLevel() != 1) {
                            continue;
                        }
                        SVGGlyph graphic = SvgGraphicUtil.buildSvgGraphic("folder-o", 12, Color.GRAY);
                        graphic.setUserData(programme.getId());
                        TreeItem<Label> iTreeItem = new TreeItem<>(new Label(programme.getTitle(),graphic));
                        iTreeItem.getValue().setUserData(1);
                        rootItem.getChildren().add(iTreeItem);
                        iTreeItem.setExpanded(true);
                        for (CustomerSearchProgramme secondLevelItem : rel) {
                            if (secondLevelItem.getLevel() != 2) {
                                continue;
                            }
                            if (!programme.getId().equals(secondLevelItem.getParentId())) {
                                continue;
                            }
                            SVGGlyph secondGraphic = SvgGraphicUtil.buildSvgGraphic("file-empty", 12, Color.GRAY);
                            secondGraphic.setUserData(secondLevelItem.getId());
                            TreeItem<Label> jTreeItem = new TreeItem<>(new Label(secondLevelItem.getTitle(),secondGraphic));
                            jTreeItem.getValue().setUserData(2);
                            iTreeItem.getChildren().add(jTreeItem);
                        }
                    }
                }).onException(Throwable::printStackTrace)
                .withFinal(() -> {
                    leftTreeView.setEditable(true);
                    leftTreeView.setOnMouseClicked(event -> {
                        EventTarget target = event.getTarget();
                        System.out.println(target);
                    });

                    leftTreeView.setCellFactory(p -> new TextFieldTreeCellImpl() {
                                @Override
                                public void getEditingText(String text) {
                                    editingProgrammeField = text;
                                    TreeItem<Label> labelTreeItem = (TreeItem<Label>)leftTreeView.getSelectionModel().getSelectedItem();
                                    TreeItem<Label> parent1 = labelTreeItem.getParent();
                                    Integer userData = (Integer)parent1.getValue().getGraphic().getUserData();

                                    Label value = labelTreeItem.getValue();
                                    value.setUserData(userData==0?1:2);
                                    Node graphic = value.getGraphic();
                                    Integer programmeId =  graphic==null?null: (Integer)graphic.getUserData();
                                    TreeItem<Label> parent = labelTreeItem.getParent();
                                    Integer parentId = (Integer)parent.getValue().getGraphic().getUserData();
                                    CustomerSearchProgramme customerSearchProgramme = CustomerSearchProgramme.builder()
                                            .actionRealm(realmName)
                                            .id(programmeId)
                                            .parentId(parentId)
                                            .level(parentId==0?1:2)
                                            .title(text)
                                            .build();
                                    saveProgramme(customerSearchProgramme,graphic);
                                }
                            }
                    );

                    leftTreeView.setShowRoot(false);
                    leftPane.getChildren().add(leftTreeView);
                })
                        .run();
    }

    private void buildTable() {
        JFXTreeTableColumn<SearchItem, String> indexColumn = new JFXTreeTableColumn<>("序号");
        indexColumn.setPrefWidth(40);
        indexColumn.setCellFactory((col) -> new TreeTableCell<SearchItem, String>() {
            @Override
            public void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                this.setText(null);
                this.setGraphic(null);

                if (!empty) {
                    int rowIndex = this.getIndex() + 1;
                    this.setText(String.valueOf(rowIndex));
                }
            }
        });

        JFXTreeTableColumn<SearchItem, CustomerBoxEditorModel> groupTagColumn = new JFXTreeTableColumn<>("组标记");
        groupTagColumn.setPrefWidth(80);
        groupTagColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<SearchItem, CustomerBoxEditorModel> param) -> {
            if (groupTagColumn.validateValue(param)) {
                return new CustomerBoxEditorModel("", param.getValue().getValue().getGroupTag().getValue());
            } else {
                return groupTagColumn.getComputedValue(param);
            }
        });

        JFXTreeTableColumn<SearchItem, CustomerBoxEditorModel> itemColumn = new JFXTreeTableColumn<>("查询项");
        itemColumn.setPrefWidth(188);
        itemColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<SearchItem, CustomerBoxEditorModel> param) -> {
            if (itemColumn.validateValue(param)) {
                return new CustomerBoxEditorModel("", param.getValue().getValue().getItemName().getValue());
            } else {
                return itemColumn.getComputedValue(param);
            }
        });

        JFXTreeTableColumn<SearchItem, String> valueColumn = new JFXTreeTableColumn<>("值");
        valueColumn.setPrefWidth(120);
        valueColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<SearchItem, String> param) -> {
            if (valueColumn.validateValue(param)) {
                return param.getValue().getValue().getValue();
            } else {
                return valueColumn.getComputedValue(param);
            }
        });

        JFXTreeTableColumn<SearchItem, CustomerBoxEditorModel> actionColumn = new JFXTreeTableColumn<>("操作");
        actionColumn.setPrefWidth(100);
        actionColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<SearchItem, CustomerBoxEditorModel> param) -> {
            if (actionColumn.validateValue(param)) {
                return new CustomerBoxEditorModel("", param.getValue().getValue().getAction().getValue());
            } else {
                return actionColumn.getComputedValue(param);
            }
        });

        JFXTreeTableColumn<SearchItem, CustomerBoxEditorModel> logicColumn = new JFXTreeTableColumn<>("逻辑");
        logicColumn.setPrefWidth(60);

        logicColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<SearchItem, CustomerBoxEditorModel> param) -> {
            if (logicColumn.validateValue(param)) {
                return new CustomerBoxEditorModel("", param.getValue().getValue().getLogic().getValue());
            } else {
                return logicColumn.getComputedValue(param);
            }
        });

        Callback<TreeTableColumn<SearchItem, String>, TreeTableCell<SearchItem, String>> cellFactory = new Callback<TreeTableColumn<SearchItem, String>, TreeTableCell<SearchItem, String>>() {
            @Override
            public TreeTableCell<SearchItem, String> call(TreeTableColumn param) {

                return new TreeTableCell<SearchItem, String>() {

                    private final ToggleButton addBut = new ToggleButton();
                    private final ToggleButton delBut = new ToggleButton();

                    {

                        addBut.getStyleClass().addAll("cf-success-but", "round");
                        addBut.setTooltip(new Tooltip("重置密码"));
                        delBut.setTooltip(new Tooltip("删除用户"));
                        delBut.getStyleClass().addAll("cf-danger-but", "round");
                        try {
                            addBut.setGraphic(SvgGraphicUtil.buildSvgGraphic("plus-square-o", 12, Color.WHITE));
                            delBut.setGraphic(SvgGraphicUtil.buildSvgGraphic("trash", 12, Color.WHITE));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        addBut.setOnMouseClicked(event -> {
                        });
                        delBut.setOnMouseClicked(event -> {
                        });

                    }

                    @Override
                    protected void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty) {
                            setGraphic(null);
                        } else {
                            HBox hBox = new HBox(addBut, delBut);
                            hBox.setSpacing(0);
                            hBox.setAlignment(Pos.CENTER);
                            setGraphic(hBox);
                        }
                    }
                };
            }
        };

//        operation.setCellFactory(
//                cellFactory
//        );
        groupTagColumn.setCellFactory(
                (TreeTableColumn<SearchItem, CustomerBoxEditorModel> param) -> new GenericEditableTreeTableCell<>(
                        new ComboBoxEditorBuilder<>(groupTagItems)
                )
        );
        groupTagColumn.setOnEditCommit((TreeTableColumn.CellEditEvent<SearchItem, CustomerBoxEditorModel> t) -> {
                    t.getTreeTableView()
                            .getTreeItem(t.getTreeTablePosition()
                                    .getRow())
                            .getValue().getGroupTag().set(t.getNewValue().getValue().toString());
                }
        );

        logicColumn.setCellFactory(
                (TreeTableColumn<SearchItem, CustomerBoxEditorModel> param) -> new GenericEditableTreeTableCell<>(
                        new ComboBoxEditorBuilder<>(logicItems)
                )
        );
        logicColumn.setOnEditCommit((TreeTableColumn.CellEditEvent<SearchItem, CustomerBoxEditorModel> t) -> t.getTreeTableView()
                .getTreeItem(t.getTreeTablePosition()
                        .getRow())
                .getValue().getLogic().set(t.getNewValue().getValue().toString()));

        actionColumn.setCellFactory((TreeTableColumn<SearchItem, CustomerBoxEditorModel> param) -> new GenericEditableTreeTableCell<>(
                new ComboBoxEditorBuilder<>(actionItems)
        ));
        actionColumn.setOnEditCommit((TreeTableColumn.CellEditEvent<SearchItem, CustomerBoxEditorModel> t) -> {
            t.getTreeTableView()
                    .getTreeItem(t.getTreeTablePosition()
                            .getRow())
                    .getValue().getAction().set(t.getNewValue().getValue().toString());
        });

        valueColumn.setCellFactory((TreeTableColumn<SearchItem, String> param) -> new GenericEditableTreeTableCell<>(
                new TextFieldEditorBuilder()));
        valueColumn.setOnEditCommit((TreeTableColumn.CellEditEvent<SearchItem, String> t) -> t.getTreeTableView()
                .getTreeItem(t.getTreeTablePosition()
                        .getRow())
                .getValue().getValue().set(t.getNewValue()));

        itemColumn.setCellFactory((TreeTableColumn<SearchItem, CustomerBoxEditorModel> param) -> new GenericEditableTreeTableCell<>(
                new ComboBoxEditorBuilder<>(customerSearchModel.getSearchItems())
        ));
        itemColumn.setOnEditCommit((TreeTableColumn.CellEditEvent<SearchItem, CustomerBoxEditorModel> t) -> t.getTreeTableView()
                .getTreeItem(t.getTreeTablePosition()
                        .getRow())
                .getValue().getItemName().set(t.getNewValue().getValue().toString()));

        // build tree
        treeView.setShowRoot(false);
        treeView.setEditable(true);
        treeView.getColumns().setAll(indexColumn, groupTagColumn, itemColumn, actionColumn, valueColumn, logicColumn);
        rightPane.getChildren().add(treeView);
    }

    private void saveProgramme(CustomerSearchProgramme customerSearchProgramme,Node graphic){
        ProcessChain.create()
                .addRunnableInPlatformThread(() -> {
                    // TODO: 2022/8/8 开始保存
                })
                .addSupplierInExecutor(
                        () -> customerSearchProgramme.getId()==null
                                ?Request.connector(CustomerSearchFeign.class).addCustomerSearchProgramme(customerSearchProgramme)
                                :Request.connector(CustomerSearchFeign.class).updateCustomerSearchProgramme(customerSearchProgramme)
                )
                .addConsumerInPlatformThread(result -> {
                    System.out.println("保存结果(id)："+result);
                    graphic.setUserData(result);
                })
                .withFinal(() -> {
                    snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(new JFXSnackbarLayout( customerSearchProgramme.getId()==null?"保存成功":"修改成功")));
                })
                .onException(Throwable::printStackTrace)
                .run();

    }

    private void removeProgramme(Integer id){
        ProcessChain.create()
                .addRunnableInPlatformThread(() -> {
                    // TODO: 2022/8/8 开始保存
                })
                .addSupplierInExecutor(
                        () -> Request.connector(CustomerSearchFeign.class).deleteCustomerSearchProgramme(id)
                )
                .addConsumerInPlatformThread(result -> {

                    System.out.println("保存结果："+result);
                })
                .withFinal(() -> {
                    // TODO: 2022/8/8 结束保存
                })
                .onException(e -> e.printStackTrace())
                .run();
    }



    private void initActions() {
        //新增方案
        addProgramme.setOnMouseClicked(e -> {
            ObservableList<TreeItem<Label>> selectedItems = leftTreeView.getSelectionModel().getSelectedItems();
            TreeItem<Label> jTreeItem = new TreeItem<>(new Label("", SvgGraphicUtil.buildSvgGraphic("file-empty", 12, Color.GRAY)));
            int itemLevel = 1;
            if (selectedItems.size() == 0) {
                TreeItem<Label> root1 = leftTreeView.getRoot();
                jTreeItem.getValue().setUserData(itemLevel);
                root1.getChildren().add(jTreeItem);
                return;
            }
            TreeItem<Label> treeItem = selectedItems.get(0);
            Object userData = treeItem.getValue().getUserData();
            if (userData != null) {
                Integer level = (Integer) userData;
                if (level >= 2) {
                    snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(new JFXSnackbarLayout("方案树仅能设置2级")));
                    return;
                } else {
                    itemLevel += 1;
                }
            }
            jTreeItem.getValue().setUserData(itemLevel);
            treeItem.getChildren().add(jTreeItem);
        });
        //删除方案
        removeProgramme.setOnMouseClicked(e -> {
            ObservableList<TreeItem> selectedItems = leftTreeView.getSelectionModel().getSelectedItems();
            if (selectedItems.size() == 0) {
                snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(new JFXSnackbarLayout("请选择要删除的数据")));
                return;
            }

            TreeItem root1 = leftTreeView.getRoot();
            cascadeRemoveLeaf(root1, selectedItems.get(0));
        });
        //编辑方案
        editProgramme.setOnMouseClicked(event -> {
            ObservableList<TreeItem> selectedItems = leftTreeView.getSelectionModel().getSelectedItems();
            if (selectedItems.size() == 0) {
                snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(new JFXSnackbarLayout("请选择要操作的数据")));
                return;
            }
            TreeItem treeItem = selectedItems.get(0);
            leftTreeView.edit(treeItem);
        });
        //新增查询条目
        addItem.setOnMouseClicked(e -> {
            searchDatas.add(new SearchItem("col12", ">", "12", " ", ""));
        });
        //删除查询条目
        removeItem.setOnMouseClicked(e -> {
            ObservableList<TreeItem<SearchItem>> selectedItems = treeView.getSelectionModel().getSelectedItems();
            if (selectedItems.size() == 0) {
                snackbar.fireEvent(new JFXSnackbar.SnackbarEvent(new JFXSnackbarLayout("请选择要删除的数据")));
                return;
            }
            TreeItem<SearchItem> searchItemTreeItem = selectedItems.get(0);
            searchDatas.remove(searchItemTreeItem.getValue());

        });
    }
}
